// Copyright Rachael Colley 2013.

package rach.grid.andgrid1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Scanner;


public class LoadGridDataFromFile {

	private WorldParameters wp;
	private String[] filePaths;
	private InputStream[] is;
	private boolean islevel0;
	private Map<Integer,Map<Integer,Map<Integer,GridCell>>> zMap;
	
	public LoadGridDataFromFile(WorldParameters wp,String[] filePaths, boolean islevel0) {
		if (wp != null) {
			
			//this.startLogWriter();
			
			this.wp = wp;
			this.filePaths = filePaths;
			this.islevel0 = islevel0;
			
			loadFromFile();
			
			//this.closeLogWriter();
		}
		else {
			// Throw
		}

	}
	
	public LoadGridDataFromFile(WorldParameters wp,InputStream[] is, boolean islevel0) {
		if (wp != null) {
			
			//this.startLogWriter();
			
			this.wp = wp;
			this.is = is;
			this.islevel0 = islevel0;
			
			loadFromFile(is);
			
			//this.closeLogWriter();
		}
		else {
			// Throw
		}

	}

	private void loadFromFile() {

		initialiseEmptyGrid(wp);
		
		//writeToLog("\nNumber of files: " + filePaths.length);

		if (filePaths != null && filePaths.length > 0) {
			if (islevel0 ==true) {
				loadFileDataForLevel0(filePaths,0);
			}
			else {
				loadFileDataForLevel(filePaths);
			}
		}
		else {
			//writeToLog("No csv files in the Directory");
			// Throw
		}


	}
	
	private void loadFromFile(InputStream[] is) {

		initialiseEmptyGrid(wp);
		
		//writeToLog("\nNumber of files: " + filePaths.length);

		if (is != null && is.length > 0) {
			if (islevel0 ==true) {
				loadFileDataForLevel0(filePaths,0); /////
			}
			else {
				loadFileDataForLevel(is);
			}
		}
		else {
			//writeToLog("No csv files in the Directory");
			// Throw
		}


	}

	private void initialiseEmptyGrid(WorldParameters wp) {
			BuildEmptyGrid beg = new BuildEmptyGrid();
			zMap = beg.buildZMap(wp);
	}

	private void loadFileDataForLevel0(String[] filePaths, int levelNumber) {
		int minZ = wp.getMinGridZ();
		int maxZ = wp.getMaxGridZ();
		int minY = wp.getMinGridY();
		int maxY = wp.getMaxGridY();
		int minX = wp.getMinGridX();
		int maxX = wp.getMaxGridX();
		for (int x = 0; x < filePaths.length; x++){
			readLevel0Data(filePaths[x],zMap.get(levelNumber),levelNumber,minY,maxY,minX,maxX, minZ, maxZ);
		}
	}

	private void loadFileDataForLevel(String[] filePaths) {
		int minZ = wp.getMinGridZ();
		int maxZ = wp.getMaxGridZ();
		int minY = wp.getMinGridY();
		int maxY = wp.getMaxGridY();
		int minX = wp.getMinGridX();
		int maxX = wp.getMaxGridX();
		for (int x = 0; x < filePaths.length; x++){
			System.out.println("now reading: " + filePaths[x]);
		}
	}
	
	private void loadFileDataForLevel(InputStream[] is) {
		int minZ = wp.getMinGridZ();
		int maxZ = wp.getMaxGridZ();
		int minY = wp.getMinGridY();
		int maxY = wp.getMaxGridY();
		int minX = wp.getMinGridX();
		int maxX = wp.getMaxGridX();
		for (int x = 0; x < is.length; x++){
			System.out.println("now reading: " + is[x]);
			readLevelData(is[x],minY,maxY,minX,maxX, minZ, maxZ);
		}
	}


	private void readLevel0Data(String fileName, Map<Integer,Map<Integer,GridCell>> yMap, int currentZLevel,int minY, int maxY, int minX, int maxX, int minZ, int maxZ) {

		//writeToLog("\n********* Now reading: " + fileName);

		int countFileTokens = 0;

		File f = null;
		Scanner sc = null;
		try {
			f = new File(fileName);
			sc = new Scanner(f);
		}
		catch (FileNotFoundException fnf) {
			String msg = "The following file could not be found and will be skipped - " + fnf.getMessage();
			//writeToLog(msg);
			return;
		}

		while (sc.hasNext()) {

			String tokenString = sc.next();
			String splitArray[] = tokenString.split(",");
			countFileTokens ++;
			try {

				if (splitArray.length >= 4) {

					int y = Integer.parseInt(splitArray[0]);
					int startX = Integer.parseInt(splitArray[1]);
					int endX = Integer.parseInt(splitArray[2]);
					String cellCategory = splitArray[3];

					if (checkTokens(startX,endX,y,currentZLevel,true,cellCategory,minY,maxY,minX,maxX,minZ,maxZ)) {

						Map<Integer,GridCell> xMap = yMap.get(y);

						for (int xCounter = startX; xCounter < endX + 1; xCounter ++ ) {

							if (this.checkGridCellExists(xMap, xCounter)==false) {
								GridCell gc = new GridCell(cellCategory, new Location(xCounter,y,currentZLevel));
								xMap.put(xCounter,gc);
							}
							else {
								String msg = "Line: " + countFileTokens + " - DUPLICATE coordinate - the following token will be discarded: " + tokenString;
								//writeToLog(msg);
							}
						}
					}

					else {
						String msg = "Line: " + countFileTokens + " - UNEXPECTED token(s) - the following value(s) in the split was not expected for this grid: " + tokenString;
						//writeToLog(msg);
					}

				}

			}

			catch (NumberFormatException ex) {
				String msg = "Line: " + countFileTokens + " - PROBLEM with number format - could not convert the following token(s) to int in the split: " + tokenString;
				//writeToLog(msg);
				continue;

			}


		}

	}
	
//	private void readLevelData(String fileName, int minY, int maxY, int minX, int maxX, int minZ, int maxZ) throws IOException {
//		readLevelData(new FileInputStream(fileName), minY, maxY, minX, maxX, minZ, maxZ);
//	}

	private void readLevelData(InputStream is, int minY, int maxY, int minX, int maxX, int minZ, int maxZ) {

		System.out.println("DOING readLevelData");
		
		//writeToLog("\n********* Now reading: " + fileName);

		int countFileTokens = 0;

		//File f = null;
		Scanner sc = null;
		//f = new File(fileName);
		sc = new Scanner(is);
		

		while (sc.hasNext()) {

			String tokenString = sc.next();
			String splitArray[] = tokenString.split(",");
			countFileTokens ++;
			try {

				if (splitArray.length >= 5) {

					int z = Integer.parseInt(splitArray[0]);
					int y = Integer.parseInt(splitArray[1]);
					int startX = Integer.parseInt(splitArray[2]);
					int endX = Integer.parseInt(splitArray[3]);
					String cellCategory = splitArray[4];

					if (checkTokens(startX,endX,y,z,false,cellCategory,minY,maxY,minX,maxX,minZ,maxZ)) {

						Map<Integer,Map<Integer,GridCell>> yMap = zMap.get(z);
						Map<Integer,GridCell> xMap = yMap.get(y);

						for (int xCounter = startX; xCounter < endX + 1; xCounter ++ ) {

							if (this.checkGridCellExists(xMap, xCounter)==false) {
								GridCell gc = new GridCell(cellCategory, new Location(xCounter,y,z));
								xMap.put(xCounter,gc);
							}
							else {
								String msg = "Line: " + countFileTokens + " - DUPLICATE coordinate - the following token will be discarded: " + tokenString;
								System.out.println(msg);
								//writeToLog(msg);
							}
						}
					}

					else {
						String msg = "Line: " + countFileTokens + " - UNEXPECTED token(s) - the following value(s) in the split was not expected for this grid: " + tokenString;
						//writeToLog(msg);
						System.out.println(msg);
					}

				}

			}

			catch (NumberFormatException ex) {
				String msg = "Line: " + countFileTokens + " - PROBLEM with number format - could not convert the following token(s) to int in the split: " + tokenString;
				//writeToLog(msg);
				System.out.println(msg);
				continue;

			}


		}

	}

	private boolean checkGridCellExists(Map<Integer,GridCell> xMap, int xKey) {
		GridCell gc = xMap.get(xKey);
		if(gc != null) return true;
		return false;
	}

	private boolean checkTokens(int startX, int endX, int y, int z, boolean isLevel0, String cellCategory, int minY, int maxY, int minX, int maxX, int minZ, int maxZ) {
		if (!checkY(y,minY,maxY)) return false;
		if (!checkX(startX,endX,minX,maxX)) return false;
		if (!checkCategory(cellCategory))return false;
		if (isLevel0 == true) {
			if (!checkZ(z,minZ,maxZ)) return false;
		}
		return true;
	}

	private boolean checkZ(int z, int minZ, int maxZ) {
		if (z < minZ || z > maxZ)return false;
		return true;
	}

	private boolean checkY(int y, int minY, int maxY) {
		if (y < minY || y > maxY)return false;
		return true;
	}

	private boolean checkX(int startX, int endX, int minX, int maxX) {
		if (startX < minX || startX > maxX)return false;
		if (endX < minX || endX > maxX)return false;
		return true;
	}

	private boolean checkCategory(String spaceCat) {
		GridCellTypeEnum.GridCellCategory[] cellCategories = GridCellTypeEnum.GridCellCategory.values();
		for (int x = 0; x < cellCategories.length; x++) {
			if (cellCategories[x].toString().equals(spaceCat)) {
				return true;
			}
		}

		return false;
	}

//	private void writeToLog(String message) {
//		writeLogs.writeLine(message);
//	}

	
	public WorldGrid getWorldGrid() {
		WorldGrid wg = new WorldGrid(wp);
		wg.setzMap(zMap);
		return wg;
	}
	
//	private void startLogWriter() {
//		writeLogs.openWriter("gridlog.txt");
//	}
//	
//	private void closeLogWriter() {
//		writeLogs.closeWriter();
//	}






}
